package com.zlyx.easy.api.http;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import com.zlyx.easy.core.utils.MethodUtils;
import com.zlyx.easy.core.utils.StringUtils;

import io.swagger.annotations.ApiOperation;
import io.swagger.models.HttpMethod;
import io.swagger.util.ReflectionUtils;

public class HttpMatch {

	private Class<?> interfaceClass;
	private Class<?> refClass;

	public HttpMatch(Class<?> interfaceClass, Class<?> refClass) {
		this.interfaceClass = interfaceClass;
		this.refClass = refClass;
	}

	public Method[] findInterfaceMethods(String methodName) throws Exception {
		Method[] methods = interfaceClass.getMethods();
		List<Method> ret = new ArrayList<Method>();
		for (Method method : methods) {
			if (method.getName().equals(methodName))
				ret.add(method);
		}
		return ret.toArray(new Method[] {});
	}

	public Method[] findRefMethods(Method[] interfaceMethods, String operationId, String requestMethod)
			throws Exception {
		List<Method> ret = new ArrayList<Method>();
		Method m = null;
		for (Method method : interfaceMethods) {
			m = refClass.getMethod(method.getName(), method.getParameterTypes());
			final ApiOperation apiOperation = ReflectionUtils.getAnnotation(m, ApiOperation.class);
			String nickname = null == apiOperation ? null : apiOperation.nickname();
			if (operationId != null) {
				if (!operationId.equals(nickname))
					continue;
			} else {
				if (StringUtils.isNotEmpty(nickname))
					continue;
			}
			if (requestMethod != null) {
				String httpMethod = null == apiOperation ? null : apiOperation.httpMethod();
				if (StringUtils.isNotEmpty(httpMethod) && !requestMethod.equals(httpMethod))
					continue;
				if (StringUtils.isEmpty(httpMethod) && !requestMethod.equalsIgnoreCase(HttpMethod.POST.name()))
					continue;
			}
			ret.add(m);
		}
		return ret.toArray(new Method[] {});
	}

	public Method matchRefMethod(Method[] refMethods, String methodName, Set<String> keySet) throws Exception {
		if (refMethods.length == 0) {
			return null;
		}
		if (refMethods.length == 1) {
			return refMethods[0];
		}

		List<RateMethod> rateMethods = new ArrayList<RateMethod>();
		for (Method method : refMethods) {
			Set<String> parameterNames = MethodUtils.getParamterMap(method).keySet();
			if (parameterNames == null)
				return method;
			float correctRate = 0.0f;
			int hit = 0;
			int error = 0;
			for (String paramName : parameterNames) {
				if (keySet.contains(paramName))
					hit++;
				else
					error++;
			}
			correctRate = error / (float) hit;

			rateMethods.add(new RateMethod(method, (int) correctRate * 100));

		}

		if (rateMethods.isEmpty())
			return null;
		Collections.sort(rateMethods, new Comparator<RateMethod>() {
			@Override
			public int compare(RateMethod o1, RateMethod o2) {
				return o2.getRate() - o1.getRate();
			}
		});

		return rateMethods.get(0).getMethod();
	}

	class RateMethod {
		private Method method;
		private int rate;

		public RateMethod(Method method, int rate) {
			this.method = method;
			this.rate = rate;
		}

		public Method getMethod() {
			return method;
		}

		public void setMethod(Method method) {
			this.method = method;
		}

		public int getRate() {
			return rate;
		}

		public void setRate(int rate) {
			this.rate = rate;
		}

	}

}
